#include<iostream>
#include<thread>
#include<vector>

using namespace std;

void myprint(){
    cout<<"start"<<endl;
}

void test01(){
    thread myobj(myprint);
    myobj.joinable();//判断是否可以成功使用join()或者detach()，false就是不可以
}

class TA{
    public:
    int m_i;
    TA(int& m): m_i(m) {}
    TA(const TA& ta ): m_i(ta.m_i){
        cout<<"这是一个拷贝函数"<<endl;
    }
    ~TA(){
        cout<<"析构函数"<<endl;
    }
    void operator()(){
        cout<<"fanghanshu "<<endl;
    }
};

void test02(){
    //其他多线程方法
    int a = 6;
    TA ta(a);  //调用datach()是不会出现ta对象被销毁，因为是直接被复制了到子进程
    thread myobj(ta);
    //  myobj.join();
    myobj.detach(); //由于是子线程引用了主线程的变量。因此，当主线程执行完成后，子线程引用这个变量就会导致错误

}

//使用lamda表达式
void test03(){
    auto mulamdathread = []{
        cout<<"线程"<<endl;
    };
    thread myobj(mulamdathread);
    myobj.detach();

}

void m_print(const int & i, char* p){
    cout<<i<<endl;
    cout<<p<<endl;
    return;
}

class A{
    int m_a;
    A(int a): m_a(a) {  //这是可以赋值int类型，然后，隐式转换成类A对象的

    } 
};

//传递临时对象作为线程参数
void test04(){
    int mvar = 1;
    int &mvary = mvar;
    char mybuf[] = "this is a test!";
    thread myobj(m_print,mvar,mybuf);  //i实际不是真正的引用，经过了复制。但是，还是不能这样引用
    //使用指针的话，一定是同一地址。
    myobj.join();

    //mybuf从char*转成string 并不是该行执行完就直接转。有可能是主线程被执行完，才会转。这就会有bug。原因就是当子线程被创建的时候，就开始子线程的运行，而detach()的话，就是
    //子线程和主线程分别运行。主线程完全可能先执行完，对象还没有转换。
    //解决办法就是  string(mybuf)这是临时转成一个string对象  
    //因为thread函数是用值传递，使用引用的话，也会把引用的值复制一份
    //显示转换，所有的A类对象都会在主线程中构造

    //总结：
    //1.如果是使用简单数据类型，int，就使用值传递，不要用引用
    //2.如果是传递类对象，避免隐式转换。子线程的函数的参数要使用引用，可以避免一次引用
}

//线程id 获取线程id  std::this_thread::get_id()

//传递类对象 智能指针作为参数
//如果要实现在子线程中改变主线程的变量 使用std::ref(变量)
//unique_ptr<int> 智能指针转给其他指针指向的时候，需要用到std::move(mvp)
//传递类方法  std::thread obj(&A::thread_work, myobj,5)


//创建等待多个线程
void test05(){
    vector<thread> mythreads;
    for(int i=0;i<10;i++){
        mythreads.push_back(thread(myprint,i));
    }
    //多个线程执行顺序是乱的，和系统调度有关
    for(auto iter = mythreads.begin();iter != mythreads.end();++iter){
        iter->join();
    }
}

//数据共享的问题
//如果数据只读，则没有什么问题
//有读有写，有问题
//最简单的处理方法：读的时候不能写，写的时候不能都，2个线程不能同时写，8个线程不能同时读

int main(){
    thread myobj(myprint);  //创建了线程，线程执行入口myprint()，myprint线程开始执行
    myobj.join();  //主线程到这里等待myprint()执行完毕，当子线程执行完毕，这个jion()就执行完。主线程继续执行。
    //如果没有join()，就是当主线程执行完了，子线程没有执行完，就会导致异常。

    //detach()主线程不等待子进程执行完。子线程失去了与主线程关联。
    //当这个子线程执行完之后，由运行时库负责清理资源
    //一旦detach()之后，就不能用join()了


    cout<<"i love china"<<endl; 

    return 0;
}

int main(){
    thread myobj(myprint);  //创建了线程，线程执行入口myprint()，myprint线程开始执行
    myobj.detach();  

    //detach()主线程不等待子进程执行完。子线程失去了与主线程关联。
    //当这个子线程执行完之后，由c++运行时库负责清理资源

    cout<<"i love china"<<endl; 

    return 0;
}